#pragma once

#include <sstream>
#include <map>
#include "../Code/tinyxml/tinyxml.h"
#include "GameObj.h"
#include "util.h"
#include <cstring>
#include <vector>
#include "Bird.h"
#include "Block.h"
#include "Pig.h"
#include <math.h>

class Config
{
	/*
	public:
	enum KeyName{KN_FRONT,KN_BACK,KN_LEFT,KN_RIGHT,LEFT_BUT,RIGHT_BUT};
	private:
	int resolutionVer,resolutionHor,volume;
	int ResolutionHor() const { return resolutionHor; }
	void ResolutionHor(int val) { resolutionHor = val; }
	int ResolutionVer() const { return resolutionVer; }
	void ResolutionVer(int val) { resolutionVer = val; }
	int Volume() const { return volume; }
	void Volume(int val) { volume = val; }
	*/
	Config(void):_doc("config.xml"){
		//load file and init root;
		init();
		//load the parameters
		parseParam();

		bool print=true;
		if(print){
			typedef std::map<std::string, std::string>::iterator It;
			for(It it = _map.begin();it!=_map.end();++it){
				std::cout<<it->first<<std::endl;
				std::cout<<it->second<<std::endl;
			}
		}
	}

	~Config(void){}

private:
	TiXmlElement * gameObjToNode(GameObj *obj){

	}
	GameObj* nodeToGameObj(TiXmlElement *u){
		Ogre::Vector3 size,pos;
		Ogre::Quaternion orient;
		for(TiXmlElement *e=u->FirstChildElement();e;e=e->NextSiblingElement()){
			if(!strcmp(e->Value(),"size")){
				nodeToVector(e,size);
			}
			else if(!strcmp(e->Value(),"pos")){
				nodeToVector(e,pos);
			}
			else if(!strcmp(e->Value(),"orient")){
				nodeToQuaternion(e,orient);
			}
			else {
				ASSERT(0);
			}
		}
		GameObj* res=0;
		if(!strcmp(u->Value(),"bird")){
			res=new Bird();
		}
		if(!strcmp(u->Value(),"block")){
			res=new Block();
		}
		if(!strcmp(u->Value(),"pig")){
			res=new Pig();
		}

		/*
		float mass;
		u->QueryFloatAttribute("mass",&mass);
		res->setMass(mass);*/

		res->init(size,pos,orient);
		return res;
	}

	std::vector<GameObj*> nodeToGameObjList(TiXmlElement *u){
		ASSERT(!strcmp(u->Value(),"objectlist"));
		std::vector<GameObj*> res;
		for(TiXmlElement *e = u->FirstChildElement();e;e=e->NextSiblingElement()){
			res.push_back(nodeToGameObj(e));
		}
		return res;
	}
	void nodeToVector(TiXmlElement *u, Ogre::Vector3 &vec){
		u->QueryFloatAttribute("x",&vec.x);
		u->QueryFloatAttribute("y",&vec.y);
		u->QueryFloatAttribute("z",&vec.z);
	}
	void nodeToQuaternion(TiXmlElement *u, Ogre::Quaternion &q){
		u->QueryFloatAttribute("x",&q.x);
		u->QueryFloatAttribute("y",&q.y);
		u->QueryFloatAttribute("z",&q.z);
		u->QueryFloatAttribute("w",&q.w);
	}

	std::map<std::string,std::string> _map;
	void nodeToParams(std::map<std::string, std::string> &str,TiXmlElement* u){
		for(TiXmlElement* e=u->FirstChildElement();e;e=e->NextSiblingElement()){
			for(TiXmlAttribute *at =e->FirstAttribute();at;at=at->Next()){
				if(at->Name()!=0&&at->Value()){
					str[at->Name()]=at->Value();
				}
			}
		}
	}

public:
	std::vector<GameObj*> getGameObjs(){
		for(TiXmlElement *e = _root->FirstChildElement();e;e=e->NextSiblingElement()){
			if(!strcmp(e->Value(),"objectlist")){ //equals 
				return nodeToGameObjList(e);
			}
		}
		std::vector<GameObj*> d;
		return d;
	}
	const std::string getParam(const std::string &str){
		return _map[str];
	}

	/*

	void findParam(){
	for(TiXmlElement *e = _root->FirstChildElement();e;e=e->NextSiblingElement()){
	if(!strcmp(e->Value(),"params")){ //equals 
	;
	}
	}
	std::vector<GameObj*> d;
	return d;
	}*/



private:
	TiXmlDocument _doc;
	TiXmlElement *_root;
	void init() 
	{
		if(!_doc.LoadFile()){
			ASSERT(0); //unable to load file
		}
		_root=_doc.RootElement();
	}


	void parseParam(){
		for(TiXmlElement * e=_root->FirstChildElement();e;e=e->NextSiblingElement()){
			if(!strcmp(e->Value(),"params")) nodeToParams(_map,e);
		}
	}

	//////////////////////////////////////////////////////////////////////////
	//read game objs

	/////////////////////////////////////////////////////////////////////////
public:
	static Config* getInstance(){
		static Config * instance =0;
		if(!instance){
			instance = new Config();
		}
		return instance;
	}

public:
	static float parseFloat(std::string str){
		return atof(str.c_str());
	}
	static int parseInt(std::string val){
		return atoi(val.c_str());
	}

private:
	TiXmlDocument *_outDoc;

	
	/**
	begin saving objects
	*/
	public:
	void saveBegin(){
		_outDoc=new TiXmlDocument();
	}
	template<typename T>
	void saveGameObjs(std::vector<T> t){
		for(std::vector<T>::const_iterator it= t.begin();it!=t.end();++it){
			TiXmlElement *elem =new TiXmlElement(it->getName().c_str()),
				*size=new TiXmlElement("size"),*pos=new TiXmlElement("pos"),*orient=new TiXmlElement("orient");
			vectorToNode(it->sceneNode->getPosition(),*pos);
			vectorToNode(it->sceneNode->getScale(),*size);
			quaternionToNode(it->sceneNode->getOrientation(),*orient);
			elem->LinkEndChild(pos);
			elem->LinkEndChild(size);
			elem->LinkEndChild(orient);
			_outDoc->LinkEndChild(elem);
		}
		///newDoc.SaveFile("output");
	}
	void saveEnd(){
		_outDoc->SaveFile("Stable.xml");
		delete _outDoc;
	}

private:
	void vectorToNode(const Ogre::Vector3& vec,TiXmlElement &u){
		//string   s   =   boost::lexical_cast <string> (1.0f);
		u.SetAttribute("x",floatToString(vec.x).c_str());
		u.SetAttribute("y",floatToString(vec.y).c_str());
		u.SetAttribute("z",floatToString(vec.z).c_str());
	}
	void quaternionToNode(const Ogre::Quaternion &vec,TiXmlElement &u){
		//string   s   =   boost::lexical_cast <string> (1.0f);
		u.SetAttribute("x",floatToString(vec.x).c_str());
		u.SetAttribute("y",floatToString(vec.y).c_str());
		u.SetAttribute("z",floatToString(vec.z).c_str());
		u.SetAttribute("w",floatToString(vec.w).c_str());
	}
	static const std::string floatToString(float f){
		std::ostringstream   oss; 
		oss<<f<<std::flush; 
		return oss.str(); 

	}
};

